11. Pandas-数据框内部操作

⭐ 本章学习目标

  • 掌握 read_csv 关键参数的使用方法
  • 理解 lociloc 两种索引方式的区别
  • 学会按索引和按值对数据框排序
  • 掌握条件筛选与 query 查询方法
  • 学会使用 applymap 进行数据变换

⭐ 数据清洗的价值

  • 数据清洗(Data Cleaning)是数据分析中最耗时的环节
  • 通常占据分析工作 60-80% 的时间
  • Pandas 提供了丰富的数据框内部操作方法

高质量数据的四个维度:

维度 含义
完整性 无缺失值或合理处理
一致性 格式统一,单位一致
准确性 值在合理范围内
唯一性 无重复记录

⭐ 平台任务:数据读取与基础操作

Listing 1
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
import pandas as pd  # 导入Pandas数据分析库
#将第一列(date)设置为索引,只读取指定的列usecols
df=pd.read_csv("https://huoran.oss-cn-shenzhen.aliyuncs.com/20230306/csv/1632645776084066304.csv",index_col=0,usecols=['date','syzg','zgpa','zgjz']).dropna()

Trade_days=df.shape[0]  # 获取数据维度信息
print(f'2022年共有{Trade_days}个交易日')  # 输出2022年共有

stock_price=df.loc['2022-03-01','zgjz']  # 按标签索引提取数据
print(f'3月第一个交易日中国建筑价格为{stock_price}元')  # 输出3月第一个交易日中国建筑价格为

df_asc=df.sort_index(ascending=True)  # 按索引排序
print(df_asc.head(8))  # 输出前几行数据
2022年共有242个交易日
3月第一个交易日中国建筑价格为5.16元
             syzg   zgpa  zgjz
date                          
2022-01-04  22.80  51.00  5.03
2022-01-05  23.08  52.07  5.02
2022-01-06  23.85  51.30  5.13
2022-01-07  24.81  52.94  5.24
2022-01-10  24.86  53.08  5.37
2022-01-11  24.52  52.86  5.38
2022-01-12  24.49  52.50  5.26
2022-01-13  23.92  52.30  5.20

⭐ read_csv 关键参数解析

  • index_col=0:将第一列(date)设为行索引
    • 便于时间序列分析和日期检索
  • usecols=[...]:只加载指定列
    • 减少内存占用,提高读取速度
  • .dropna():链式操作,读取后立即删除缺失值
# 链式操作写法(推荐)
df = (pd.read_csv(url)
       .dropna()
       .sort_index())

⭐ 数据框基础属性一览

Listing 2
import pandas as pd
df = pd.read_csv(
    'https://huoran.oss-cn-shenzhen.aliyuncs.com/20230306/csv/1632645776084066304.csv',
    index_col=0,
    usecols=['date','syzg','zgpa','zgjz']
).dropna()

# 数据框形状
print(f'数据框形状: {df.shape}')
print(f'  - 行数(交易日): {df.shape[0]}')
print(f'  - 列数(股票): {df.shape[1]}')
数据框形状: (242, 3)
  - 行数(交易日): 242
  - 列数(股票): 3

⭐ 查看索引与列名信息

Listing 3
# 索引信息
print(f'索引类型: {type(df.index)}')
print(f'索引范围: {df.index.min()}{df.index.max()}')

# 列名
print(f'\n列名(股票代码):')
print(df.columns.tolist())
# syzg(三一重工)、zgpa(中国平安)、zgjz(中国建筑)

# 数据类型
print(f'\n数据类型:')
print(df.dtypes)
索引类型: <class 'pandas.core.indexes.base.Index'>
索引范围: 2022-01-04 到 2022-12-30

列名(股票代码):
['syzg', 'zgpa', 'zgjz']

数据类型:
syzg    float64
zgpa    float64
zgjz    float64
dtype: object

⭐ loc 标签索引:获取特定值

  • loc 使用标签(行名/列名)进行选择
  • 切片包含末端(与 Python 标准切片不同)
Listing 4
# 获取特定日期的单个值
stock_price = df.loc['2022-03-01', 'zgjz']
print(f'3月第一个交易日中国建筑价格: {stock_price}元')
3月第一个交易日中国建筑价格: 5.16元

⭐ loc 标签索引:切片与多列选择

Listing 5
# 选择日期范围 + 指定列
subset = df.loc[
    '2022-03-01':'2022-03-05',  # 行切片(包含两端)
    ['syzg', 'zgpa']            # 指定列名列表
]
print('3月1-5日, 三一重工和中国平安的价格:')
print(subset)
3月1-5日, 三一重工和中国平安的价格:
Empty DataFrame
Columns: [syzg, zgpa]
Index: []

⭐ loc 标签索引:布尔条件筛选

Listing 6
# 布尔条件筛选
print('三一重工价格>20的交易日:')
syzg_high = df.loc[df.syzg > 20]
print(syzg_high)
三一重工价格>20的交易日:
             syzg   zgpa  zgjz
date                          
2022-02-25  20.17  51.40  5.07
2022-02-24  20.19  51.46  5.15
2022-02-23  20.75  52.89  5.30
2022-02-22  20.38  53.07  5.39
2022-02-21  20.78  54.16  5.46
2022-02-18  20.89  54.50  5.50
2022-02-17  20.75  53.65  5.36
2022-02-16  20.82  53.84  5.41
2022-02-15  20.75  53.28  5.31
2022-02-14  20.46  53.90  5.35
2022-02-11  20.82  55.59  5.60
2022-02-10  21.21  54.18  5.46
2022-02-09  21.19  53.04  5.41
2022-02-08  21.25  53.00  5.49
2022-02-07  20.74  51.98  5.48
2022-01-28  20.14  49.97  5.20
2022-01-27  20.73  50.79  5.37
2022-01-26  21.97  51.83  5.38
2022-01-25  21.81  51.20  5.30
2022-01-24  22.75  53.13  5.41
2022-01-21  23.18  53.55  5.33
2022-01-20  24.25  53.40  5.40
2022-01-19  24.35  51.45  5.37
2022-01-18  23.54  51.23  5.28
2022-01-17  23.42  50.94  4.99
2022-01-14  23.38  51.10  5.02
2022-01-13  23.92  52.30  5.20
2022-01-12  24.49  52.50  5.26
2022-01-11  24.52  52.86  5.38
2022-01-10  24.86  53.08  5.37
2022-01-07  24.81  52.94  5.24
2022-01-06  23.85  51.30  5.13
2022-01-05  23.08  52.07  5.02
2022-01-04  22.80  51.00  5.03
  • df.syzg > 20 返回布尔 Series
  • loc 用这个布尔 Series 来筛选行

⭐ iloc 位置索引:基于整数位置

  • iloc 使用整数位置进行选择
  • 切片不包含末端(标准 Python 切片规则)
Listing 7
# 前5行前2列
print('前5行前2列:')
print(df.iloc[:5, :2])

# 特定位置的单个值
print(f'\n第1行第1列: {df.iloc[0, 0]}')

# 负索引(倒数第3行)
print(f'\n倒数第3行:')
print(df.iloc[-3])
前5行前2列:
             syzg   zgpa
date                    
2022-12-30  15.80  47.00
2022-12-29  15.66  45.82
2022-12-28  15.84  46.28
2022-12-27  16.18  45.58
2022-12-26  16.21  44.66

第1行第1列: 15.8

倒数第3行:
syzg    23.85
zgpa    51.30
zgjz     5.13
Name: 2022-01-06, dtype: float64

⭐ loc 与 iloc 对比总结

特性 loc iloc
索引方式 标签(行名/列名) 整数位置
切片末端 包含末端 不包含末端
适用场景 按日期/列名查询 按位置批量提取
示例 df.loc['2022-03-01'] df.iloc[0]

⭐ sort_index:按索引排序

Listing 8
# 升序排序(从早到晚)
df_asc = df.sort_index(ascending=True)
print('升序排序(日期从早到晚):')
print(df_asc.head(5))

# 降序排序(从晚到早)
df_desc = df.sort_index(ascending=False)
print(f'\n降序排序(日期从晚到早):')
print(df_desc.head(3))
升序排序(日期从早到晚):
             syzg   zgpa  zgjz
date                          
2022-01-04  22.80  51.00  5.03
2022-01-05  23.08  52.07  5.02
2022-01-06  23.85  51.30  5.13
2022-01-07  24.81  52.94  5.24
2022-01-10  24.86  53.08  5.37

降序排序(日期从晚到早):
             syzg   zgpa  zgjz
date                          
2022-12-30  15.80  47.00  5.43
2022-12-29  15.66  45.82  5.32
2022-12-28  15.84  46.28  5.39
  • 时间序列分析的前提:确保数据按时间顺序排列

⭐ sort_values:按列值排序

Listing 9
# 按单列排序(找出最高价交易日)
print('按三一重工价格降序:')
df_sorted = df.sort_values('syzg', ascending=False)
print(df_sorted.head())
按三一重工价格降序:
             syzg   zgpa  zgjz
date                          
2022-01-10  24.86  53.08  5.37
2022-01-07  24.81  52.94  5.24
2022-01-11  24.52  52.86  5.38
2022-01-12  24.49  52.50  5.26
2022-01-19  24.35  51.45  5.37

⭐ sort_values:多列排序

Listing 10
# 先按syzg升序, 再按zgpa降序
print('先按syzg升序, 再按zgpa降序:')
df_multi_sort = df.sort_values(
    ['syzg', 'zgpa'],
    ascending=[True, False]
)
print(df_multi_sort.head())
先按syzg升序, 再按zgpa降序:
             syzg   zgpa  zgjz
date                          
2022-10-31  13.50  36.15  4.75
2022-10-11  13.61  41.20  5.13
2022-10-10  13.69  41.43  5.22
2022-09-29  13.85  41.32  5.01
2022-09-30  13.88  41.58  5.15
  • 第一排序键相同时,才看第二排序键

⭐ 条件筛选:单条件

Listing 11
# 单条件筛选
print('三一重工>20:')
print(df[df.syzg > 20].head())
三一重工>20:
             syzg   zgpa  zgjz
date                          
2022-02-25  20.17  51.40  5.07
2022-02-24  20.19  51.46  5.15
2022-02-23  20.75  52.89  5.30
2022-02-22  20.38  53.07  5.39
2022-02-21  20.78  54.16  5.46
  • df.syzg > 20 返回布尔 Series
  • 用布尔 Series 作为索引,筛选出满足条件的行

⭐ 条件筛选:多条件组合

Listing 12
# AND 条件:两个条件同时满足
print('三一重工>20 且 中国平安>40:')
print(df[(df.syzg > 20) & (df.zgpa > 40)].head())

# OR 条件:满足其中一个即可
print(f'\n三一重工>30 或 中国平安>45:')
print(df[(df.syzg > 30) | (df.zgpa > 45)].head())
三一重工>20 且 中国平安>40:
             syzg   zgpa  zgjz
date                          
2022-02-25  20.17  51.40  5.07
2022-02-24  20.19  51.46  5.15
2022-02-23  20.75  52.89  5.30
2022-02-22  20.38  53.07  5.39
2022-02-21  20.78  54.16  5.46

三一重工>30 或 中国平安>45:
             syzg   zgpa  zgjz
date                          
2022-12-30  15.80  47.00  5.43
2022-12-29  15.66  45.82  5.32
2022-12-28  15.84  46.28  5.39
2022-12-27  16.18  45.58  5.41
2022-12-23  16.14  45.64  5.42
  • & 逻辑与(AND),| 逻辑或(OR)
  • 每个条件必须加括号

⭐ 条件筛选:isin 成员检查

Listing 13
# 选择特定日期的数据
dates_to_check = ['2022-03-01', '2022-03-02', '2022-03-03']
print('特定日期的数据:')
print(df.loc[dates_to_check])
特定日期的数据:
             syzg   zgpa  zgjz
date                          
2022-03-01  19.74  51.39  5.16
2022-03-02  19.50  50.76  5.20
2022-03-03  19.43  50.92  5.49
  • 等价于 df[df.index.isin(dates_to_check)]

⭐ query 方法:更直观的查询语法

Listing 14
# 简单条件(类似SQL语法)
result1 = df.query('syzg > 20')
print('syzg > 20:')
print(result1.head())

# 多条件(使用 and/or/not)
result2 = df.query('syzg > 20 and zgpa < 40')
print(f'\nsyzg > 20 and zgpa < 40:')
print(result2.head())
syzg > 20:
             syzg   zgpa  zgjz
date                          
2022-02-25  20.17  51.40  5.07
2022-02-24  20.19  51.46  5.15
2022-02-23  20.75  52.89  5.30
2022-02-22  20.38  53.07  5.39
2022-02-21  20.78  54.16  5.46

syzg > 20 and zgpa < 40:
Empty DataFrame
Columns: [syzg, zgpa, zgjz]
Index: []

⭐ query 方法:引用外部变量

Listing 15
# 使用@引用外部变量
threshold = 25
result3 = df.query('syzg > @threshold')
print(f'syzg > {threshold}:')
print(result3.head())
syzg > 25:
Empty DataFrame
Columns: [syzg, zgpa, zgjz]
Index: []
  • @变量名:在 query 中引用 Python 环境变量
  • 优势:语法更简洁,可读性更高

⭐ apply:对行或列应用函数

Listing 16
# 对每列应用函数(计算极差)
print('每列的极差(最高价-最低价):')
print(df.apply(lambda x: x.max() - x.min()))

# 对每行应用函数(计算均值)
print(f'\n每行的均值(每日三只股票平均):')
print(df.apply(lambda x: x.mean(), axis=1).head())
每列的极差(最高价-最低价):
syzg    11.36
zgpa    19.44
zgjz     1.54
dtype: float64

每行的均值(每日三只股票平均):
date
2022-12-30    22.743333
2022-12-29    22.266667
2022-12-28    22.503333
2022-12-27    22.390000
2022-12-26    22.080000
dtype: float64
  • axis=0(默认):沿列方向操作
  • axis=1:沿行方向操作(跨列计算)

⭐ map:对 Series 逐元素变换

Listing 17
# 定义价格分类函数
def categorize_price(price):
    if price > 30:
        return '高'
    elif price > 20:
        return '中'
    else:
        return '低'

# 对syzg列逐元素应用
syzg_category = df['syzg'].map(categorize_price)
print('三一重工价格分类(前10个):')
print(syzg_category.head(10))
三一重工价格分类(前10个):
date
2022-12-30    低
2022-12-29    低
2022-12-28    低
2022-12-27    低
2022-12-26    低
2022-12-23    低
2022-12-22    低
2022-12-21    低
2022-12-20    低
2022-12-19    低
Name: syzg, dtype: object
  • map 只用于 Series,对每个元素逐个应用函数

⭐ apply 与 map 对比总结

特性 apply map
适用对象 DataFrame 或 Series 仅 Series
操作维度 按行或按列 逐元素
常见用途 聚合统计、跨列计算 值替换、分类映射
示例 df.apply(func, axis=1) series.map(func)

⭐ 本章小结

  • 数据读取read_csvindex_colusecols 等参数
  • 标签索引loc 按标签选择,切片包含末端
  • 位置索引iloc 按整数位置,切片不含末端
  • 排序sort_index 按索引,sort_values 按值
  • 筛选:布尔条件(&/|)与 query 方法
  • 变换apply 按行/列操作,map 逐元素操作